查看原文
其他

火车票上的星号暗藏玄机?!

LBS 2022-10-05

前言


        春运马上要到了,你可能觉得身份证打了四个星号,就可以随手一丢,但是是否意味着安全啦?



通过百度简单的搜索一下,百度:火车票,搜索

详细分析


        1.寻找数据源


        我们随便选择一个:


就这位了

        2.四位星号分析


        现在我们来分析一下这四位星号,从身份证的构造上看 肯定是 月日,二个字节表示月或者日,假如四个星号为(ABCD)


        那么A 代表的是月 大家都知道月最多是12月 那么A 最大是1,


        那么只有二种选择(0,1),


        好现在我们开始判断一下B的取值范围:


当A为0的时候B取值为(1-9)

 当A为1的时候B取值为(0-2)


        现在来判断C的范围,大家都知道一个月最多31天,


那么C的范围(0-3)


        现在判断一下D的范围


当C为0的时候D为1-9 

当C为1-2的时候D为0-9

当C为3的时候D为0-1


        大家别嫌弃我分析麻烦,如果不分析,怎么写代码?

        3.写代码生成数据


//月左位for (size_t iA = 0; iA < 2; iA++) {//月右位for (size_t iB = 0; iB < 10; iB++) {//当A为0的时候B取值为(1 - 9)if (iA==0) {if (iB==0) {continue; } }else if (iA == 1) //当A为1的时候B取值为(0-2){if (iB > 2) {continue; } }//日的左边for (size_t iC = 0; iC < 4; iC++) {//日的右边for (size_t iD = 0; iD < 10; iD++) {//当C为0的时候D为1-9if (iC==0) {if (iD == 0) {continue; } }else if (iC == 3)//当C为3的时候D为0 - 1{if (iD > 1) {continue; } }sprintf(buffer, "%s%d%d%d%d%s", pFrist,iA, iB, iC, iD, pEnd);if (!Chk18PaperId(buffer)) { WriteFile(hFile, buffer, strlen(buffer), &dwWrite, NULL); WriteFile(hFile, "\r\n", 2, &dwWrite, NULL); } } } } }


        4.数据进行过滤


        根据月大月小过滤一下数据,1.3.5.7.8.10.12 是月大 2月只有28天


//开始遍历 //1 3 5 7 8 10 12 月大//进行月大月小的判断if (iA==0) {if (iB == 4 || iB == 6 || iB == 9 || iB == 11) {//月小if (iC == 3 && iD == 1) {continue; } }else if (iB==2) {//月小if (iC > 2) {continue; }else if (iC==2&&(iD>8)) {continue; } } }else{if (iB==1) {//11月是月小if (iC==3&&iD==1) {continue; } } }



        少了几条啊


        5.数据再次过滤


        一共有三百多条数据,我们需要进一步进行过滤,过滤原理如下


        校验规则是:


        (1)十七位数字本体码加权求和公式 


        S = Sum(Ai * Wi), i = 0, … , 16 ,先对前17位数字的权求和 

        Ai:表示第i位置上的身份证号码数字值 

        Wi:表示第i位置上的加权因子 

        Wi: 7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2 


        (2)计算模 

        Y = mod(S, 11) 


        (3)通过模得到对应的校验码 

        Y: 0 1 2 3 4 5 6 7 8 9 10 

        校验码: 1 0 X 9 8 7 6 5 4 3 2


int Chk18PaperId(const char *sPaperId){long lSumQT = 0;//加权因子  int R[] = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };//校验码  char sChecker[11] = { '1','0','X', '9', '8', '7', '6', '5', '4', '3', '2' };//检验长度  if (18 != strlen(sPaperId)) return -1;//校验数字  for (int i = 0; i<18; i++) {if (!isdigit(sPaperId[i]) && !(('X' == sPaperId[i] || 'x' == sPaperId[i]) && 17 == i)) {return -1; } }//验证最末的校验码  for (int i = 0; i <= 16; i++) { lSumQT += (sPaperId[i] - 48) * R[i]; }if (sChecker[lSumQT % 11] != sPaperId[17]) {return -1; }return 0; }


看计算后的结果



这个结果还是比较满意的,只有三十多次了


        6.数据验证


        最后一步,数据验证



        根据姓名和上传生成的30多个身份证id取验证一下吧


        随机选择了一家,代码如下 大同小异,关于最后身份证号码是多少?   

        

        在此保密,自己验证



        验证测试代码


#include<Windows.h>#include<stdio.h>/*************************************************** * 函 数 名: Chk18PaperId * * 函数功能: 校验18位身份证号码 * * 输入参数:  sPaperId  身份证号 * * 输出参数: * * 返回值:   0        成功 *           其他     失败 ****************************************************/int Chk18PaperId(const char *sPaperId){long lSumQT = 0;//加权因子  int R[] = { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };//校验码  char sChecker[11] = { '1','0','X', '9', '8', '7', '6', '5', '4', '3', '2' };//检验长度  if (18 != strlen(sPaperId)) return -1;//校验数字  for (int i = 0; i<18; i++) {if (!isdigit(sPaperId[i]) && !(('X' == sPaperId[i] || 'x' == sPaperId[i]) && 17 == i)) {return -1; } }//验证最末的校验码  for (int i = 0; i <= 16; i++) { lSumQT += (sPaperId[i] - 48) * R[i]; }if (sChecker[lSumQT % 11] != sPaperId[17]) {return -1; }return 0; }void CreateId(char * pFrist, char * pEnd){char buffer[MAX_PATH] = { 0 }; DWORD dwWrite = 0; HANDLE hFile = CreateFileA("1.txt",  FILE_WRITE_ACCESS, NULL, NULL, OPEN_ALWAYS, NULL, NULL);//月左位for (size_t iA = 0; iA < 2; iA++) {//月右位for (size_t iB = 0; iB < 10; iB++) {//当A为0的时候B取值为(1 - 9)if (iA==0) {if (iB==0) {continue; } }else if (iA == 1) //当A为1的时候B取值为(0-2){if (iB > 2) {continue; } }//日的左边for (size_t iC = 0; iC < 4; iC++) {//日的右边for (size_t iD = 0; iD < 10; iD++) {//当C为0的时候D为1-9if (iC==0) {if (iD == 0) {continue; } }else if (iC == 3)//当C为3的时候D为0 - 1{if (iD > 1) {continue; } }//开始遍历 //1 3 5 7 8 10 12 月大//进行月大月小的判断if (iA==0) {if (iB == 4 || iB == 6 || iB == 9 || iB == 11) {//月小if (iC == 3 && iD == 1) {continue; } }else if (iB==2) {//月小if (iC > 2) {continue; }else if (iC==2&&(iD>8)) {continue; } } }else{if (iB==1) {//11月是月小if (iC==3&&iD==1) {continue; } } }sprintf(buffer, "%s%d%d%d%d%s", pFrist,iA, iB, iC, iD, pEnd);if (!Chk18PaperId(buffer)) { WriteFile(hFile, buffer, strlen(buffer), &dwWrite, NULL); WriteFile(hFile, "\r\n", 2, &dwWrite, NULL); } } } } } CloseHandle(hFile); }void main(){ CreateId("2113241992", "3014"); }


最后总结


        希望大家注意火车票的隐私,千万别乱丢火车票,同时提醒12306给校验码去掉,这样就增加了难度



您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存